using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Xml.XPath;
using Lucene.Net.Analysis;
using SearchTools.Exceptions;
using SearchTools.Logging;
using SearchTools.Providers;
using StructureMap;
using umbraco;

namespace Searchtools.Providers
{
    /// <summary>
    /// User metadata provider for umbraco CMS
    /// </summary>
    [Pluggable("MemberUnstructured")]
    public class Member : IMetadataProvider
    {
        #region IMetadataProvider Members

        /// <summary>
        /// Return value for field for current item 
        /// </summary>
        /// <param name="field">Field specifier</param>
        /// <returns>Term list</returns>
        public Dictionary<string, int> this[string field]
        {
            get
            {
                try
                {
                    XPathNavigator memberXml = library.GetCurrentMember().Current;

                    return GetTerms(field, memberXml);
                }
                catch (Exception e)
                {
                    Logger.Write("Error", "Failed to get terms for user ", e);
                }

                return new Dictionary<string, int>();
            }
        }

        /// <summary>
        /// Return value for field for item specified by key
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <returns>Term list</returns>
        public Dictionary<string, int> this[string key, string field]
        {
            get
            {
                try
                {
                    XPathNavigator memberXml = library.GetMember(Convert.ToInt32(key)).Current;

                    return GetTerms(field, memberXml);
                }
                catch (Exception e)
                {
                    Logger.Write("Error", "Failed to get terms for user ", e);
                }

                return new Dictionary<string, int>();
            }
        }

        #endregion

        private static Dictionary<string, int> GetTerms(string field, XPathNavigator memberXml)
        {
            XPathNodeIterator data = memberXml.Select("./@" + field);

            if (data.MoveNext())
            {
                return GetTermsFromNode(data);
            }

            data = memberXml.Select("./data[@alias='" + field + "']");

            if (data.MoveNext())
            {
                return GetTermsFromNode(data);
            }

            throw new SearchToolsException(string.Format("Cannot locate node attribute or data '{0}'", field));
        }

        private static Dictionary<string, int> GetTermsFromNode(XPathNodeIterator data)
        {
            Dictionary<string, int> scratch = new Dictionary<string, int>();
            StopAnalyzer anal = new StopAnalyzer(new FileInfo("DefaultStopWords.txt"));

            TokenStream tStr = anal.TokenStream("", new StringReader(
                                                        Regex.Replace(data.Current.Value, "<[^>]*>", "")));

            Token tok = tStr.Next();
            while (tok != null)
            {
                if (!scratch.ContainsKey(tok.TermText()))
                {
                    scratch.Add(tok.TermText(), 1);
                }
                else
                {
                    ++scratch[tok.TermText()];
                }

                tok = tStr.Next();
            }

            return scratch;
        }
    }

    /// <summary>
    /// Member metadata provider
    /// </summary>
    [Pluggable("MemberStructuredAsCSV", "")]
    public class MemberStructuredAsCSV : IMetadataProvider
    {
        #region IMetadataProvider Members

        /// <summary>
        /// Return value for field for current item 
        /// </summary>
        /// <param name="field">Field specifier</param>
        /// <returns>Term list</returns>
        public Dictionary<string, int> this[string field]
        {
            get
            {
                try
                {
                    XPathNavigator memberXml = library.GetCurrentMember().Current;

                    return GetTerms(field, memberXml);
                }
                catch (Exception e)
                {
                    Logger.Write("Error", "Failed to get terms for user ", e);
                }

                return new Dictionary<string, int>();
            }
        }

        /// <summary>
        /// Return value for field for item specified by key
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <returns>Term list</returns>
        public Dictionary<string, int> this[string key, string field]
        {
            get
            {
                try
                {
                    XPathNavigator memberXml = library.GetMember(Convert.ToInt32(key)).Current;

                    return GetTerms(field, memberXml);
                }
                catch (Exception e)
                {
                    Logger.Write("Error", "Failed to get terms for user ", e);
                }

                return new Dictionary<string, int>();
            }
        }

        #endregion

        private static Dictionary<string, int> GetTerms(string field, XPathNavigator memberXml)
        {
            XPathNodeIterator data = memberXml.Select("./@" + field);

            if (data.MoveNext())
            {
                return SplitCSVToTerms(data);
            }

            data = memberXml.Select("./data[@alias='" + field + "']");

            if (data.MoveNext())
            {
                return SplitCSVToTerms(data);
            }

            throw new SearchToolsException(string.Format("Cannot locate node attribute or data '{0}'", field));
        }

        private static Dictionary<string, int> SplitCSVToTerms(XPathNodeIterator data)
        {
            Dictionary<string, int> ret = new Dictionary<string, int>();

            string[] terms = data.Current.Value.Split(',');
            foreach (string term in terms)
            {
                if (ret.ContainsKey(term))
                {
                    ++ret[term];
                }
                else
                {
                    ret.Add(term, 1);
                }
            }

            return ret;
        }
    }
}